/*
 * @Description: AT24C16C EEPROM 驱动
 * @Author: diyhome
 * @Date: 2020-08-08 22:18
 * @File: AT24C16C
*/

#include "AT24C16C.h"
I2C_HandleTypeDef *AT24C16_IIC_NAME;

HAL_StatusTypeDef AT24Cx_Write_AnyBytes(uint8_t *data, uint16_t addr, uint16_t data_len) {
    if (addr + data_len >= EEPROM_SIZE) return HAL_ERROR;
    while (data_len > 0){
        uint16_t Device_Addr = 0xA0 + ((addr >> 8) << 1);
        uint8_t Mem_Addr = addr & 0xFF;

        uint8_t current_allow_write_bytes = EEPROM_PAGE_MASK - (addr & (EEPROM_PAGE_MASK - 1));         // 计算当前页还可以继续写入多少个Byte
        current_allow_write_bytes >= data_len ? data_len : current_allow_write_bytes;                   // 如果当前页可写入的Byte大于待写入的Byte则取待写入的Byte避免后面的数据被破坏

        /**
        * 这个地方要等AT24Cx内部写入完成后才能再次写入,本着能不用延时就不用延时的想法不打算死等
        * 如果写入成功返回HAL_OK则直接跳出这个循环
        * 用循环的原因是防止多次写入失败造成系统阻塞
        */
        uint16_t i = 0;
        for (i = 0; i < AT24Cx_FAIL_RETRIES; ++i) {
            if (HAL_I2C_Mem_Write(AT24C16_IIC_NAME, Device_Addr, Mem_Addr, AT24Cx_MEM_ADD, data, current_allow_write_bytes, AT24Cx_TIME_OUT) == HAL_OK) break;
        }
        if (i == AT24Cx_FAIL_RETRIES) return HAL_ERROR;

        data_len -= current_allow_write_bytes;
        data += current_allow_write_bytes;
        addr += current_allow_write_bytes;
    }
    return HAL_OK;
}

HAL_StatusTypeDef AT24Cx_Read_AnyBytes(uint8_t *data, uint16_t addr, uint16_t data_len) {
    if (addr + data_len >= EEPROM_SIZE) return HAL_ERROR;       // 判断读取数据大小是否超出存储器大小
    uint16_t Device_Addr = 0xA1 + ((addr >> 8) << 1);           // 设备地址: 1010(器件固有值) + 三Bit片选 + 0 (写入标志)
    uint8_t Mem_Addr = addr & 0xFF;                             // 器件内部地址,取低八位
    return HAL_I2C_Mem_Read(AT24C16_IIC_NAME, Device_Addr, Mem_Addr, AT24Cx_MEM_ADD, data, data_len, AT24Cx_TIME_OUT);
}

void Scan_IIC_Device_Id(I2C_HandleTypeDef *iic_port) {
#ifndef AT24C16_IIC_NAME
    iic_port = AT24C16_IIC_NAME;
#endif
    uint8_t i = 0;
    HAL_StatusTypeDef status;
    for (i = 0; i < 255; i++) {
        status = HAL_I2C_Master_Transmit(&hi2c2, i << 1, 0, 0, 200);
        if (status == HAL_OK) {
            printf("i2c addr:0x%02X is ok\r\n", i << 1);
        } else if (status == HAL_TIMEOUT) {
            printf("i2c addr:0x%02X is timeout\r\n", i << 1);
        } else if (status == HAL_BUSY) {
            printf("i2c addr:0x%02X is busy\r\n", i << 1);
        }
    }
    printf("scan end\r\n");
}

HAL_StatusTypeDef AT24Cx_Init(I2C_HandleTypeDef *hi2c_id) {
    AT24C16_IIC_NAME = hi2c_id;
    return HAL_OK;
}
